#pragma	once

#include <string>
#include <boost/type_traits.hpp>
#include <Loki/TypeManip.h>

namespace	Z	{

//------------------------------------------------------------------------------------------------------------------------
struct	Streamable
{
	virtual	void	read(void* data, size_t kSize)	= 0;
	virtual	void	write(const void* data, size_t kSize)	= 0;
};

}

namespace	ZImpl	{

//------------------------------------------------------------------------------------------------------------------------
using	namespace	Z;

template<typename T>	Streamable&	put(Streamable& streamable, const T& value, Loki::Int2Type<true>)	{
	streamable.write((const void*)&value, sizeof(T));
	return streamable;
}

template<typename T>	Streamable&	put(Streamable& streamable, const T& value, Loki::Int2Type<false>)	{
	value.serialize(streamable);
	return streamable;
}

template<typename T>	Streamable&	get(Streamable& streamable, T& value, Loki::Int2Type<true>)	{
	streamable.read((void*)&value, sizeof(T));
	return streamable;
}

template<typename T>	Streamable&	get(Streamable& streamable, T& value, Loki::Int2Type<false>)	{
	value.deserialize(streamable);
	return streamable;
}

}

namespace	Z	{

//------------------------------------------------------------------------------------------------------------------------
template<typename T>	inline	Streamable&	operator<<(Streamable& streamable, const T& value)	{
	const bool isStreamable	= !(boost::is_pointer<T>::value || boost::is_polymorphic<T>::value);
	return ZImpl::put(streamable, value, Loki::Int2Type<isStreamable>());
}

template<typename T>	inline	Streamable&	operator >>(Streamable& streamable, T& value)	{
	const bool isStreamable	= !(boost::is_pointer<T>::value || boost::is_polymorphic<T>::value);
	return ZImpl::get(streamable, value, Loki::Int2Type<isStreamable>());
}

_ZMainApi	void	writeString(Streamable& streamable, const char* str);
_ZMainApi	void	readString(Streamable& streamable, char* str, size_t kSize);
_ZMainApi	void	writeString(Streamable& streamable, const std::string& str);
_ZMainApi	void	readString(Streamable& streamable, std::string& str, size_t kSize);

}